package org.wgc.study.job;

/***
 *@title BloginfoJob
 *@description <TODO description class purpose>
 *@author wgc_j
 *@version 1.0.0
 *@create 2025-08-08 9:18
 **/

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.batch.MyBatisCursorItemReader;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.wgc.study.entity.Bloginfo;
import org.wgc.study.listner.MyBeanValidator;
import org.wgc.study.listner.MyJobListener;
import org.wgc.study.listner.MyReadListener;
import org.wgc.study.listner.MyWriteListener;
import org.wgc.study.process.MyItemProcessorNew;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Component
public class BloginfoJob {

    /**
     * 定义job
     *
     * @param jobs
     * @param stepNew
     * @return
     */
    @Bean
    public Job myJobNew(JobBuilderFactory jobs, Step stepNew) {
        return jobs.get("myJobNew").incrementer(new RunIdIncrementer()).flow(stepNew).end().listener(myJobListener()).build();

    }

    @Bean
    public Step stepNew(StepBuilderFactory stepBuilderFactory, MyBatisCursorItemReader<Bloginfo> itemReaderNew, ItemWriter<Bloginfo> writerNew, ItemProcessor<Bloginfo, Bloginfo> processorNew) {
        return stepBuilderFactory.get("stepNew").<Bloginfo, Bloginfo>chunk(65000) // Chunk的机制(即每次读取一条数据，再处理一条数据，累积到一定数量后再一次性交给writer进行写入操作)
                .reader(itemReaderNew).faultTolerant().retryLimit(3).retry(Exception.class).skip(Exception.class).skipLimit(10).listener(new MyReadListener()).processor(processorNew).writer(writerNew).faultTolerant().skip(Exception.class).skipLimit(2).listener(new MyWriteListener()).build();

    }

    public MyJobListener myJobListener() {
        return new MyJobListener();
    }
    @Bean
    public ItemProcessor<Bloginfo, Bloginfo> processorNew() {
        MyItemProcessorNew csvItemProcessor = new MyItemProcessorNew();
        // 设置校验器
        csvItemProcessor.setValidator(myBeanValidator());
        return csvItemProcessor;
    }
    public MyBeanValidator myBeanValidator(){
        return new MyBeanValidator<Bloginfo>();
    }
    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Bean
    @StepScope
// Spring Batch提供了一个特殊的bean scope类（StepScope:作为一个自定义的Spring bean scope）。这个step scope的作用是连接batches的各个steps。这个机制允许配置在Spring的beans当steps开始时才实例化并且允许你为这个step指定配置和参数。
    public MyBatisCursorItemReader<Bloginfo> itemReaderNew(@Value("#{jobParameters[authorId]}") String authorId) {

        System.out.println("开始查询数据库");

        MyBatisCursorItemReader<Bloginfo> reader = new MyBatisCursorItemReader<>();

        reader.setQueryId("org.wgc.study.mapper.BloginfoMapper.queryInfoById");

        reader.setSqlSessionFactory(sqlSessionFactory);
        Map<String, Object> map = new HashMap<>();

        map.put("authorId", Integer.valueOf(authorId));
        reader.setParameterValues(map);
        return reader;
    }

    /**
     * ItemWriter定义：指定datasource，设置批量插入sql语句，写入数据库
     *
     * @param dataSource
     * @return
     */
    @Bean
    public ItemWriter<Bloginfo> writerNew(DataSource dataSource) {
        // 使用jdbcBcatchItemWrite写数据到数据库中
        JdbcBatchItemWriter<Bloginfo> writer = new JdbcBatchItemWriter<>();
        // 设置有参数的sql语句
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Bloginfo>());
        String sql = "insert into bloginfonew " + " (blogAuthor,blogUrl,blogTitle,blogItem) " + " values(:blogAuthor,:blogUrl,:blogTitle,:blogItem)";
        writer.setSql(sql);
        writer.setDataSource(dataSource);
        return writer;
    }
}
